Conversation
Introduces a new inline block for embedding images within rich text content. Supports float left/right with text wrapping and inline positioning with configurable vertical alignment. Registered in defaultLexical and Posts collection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ible caption Replace small/medium/large presets with more flexible sizing options: original, 25/50/75/100% container width, and fixed pixel height. Caption now renders as visible text below the image instead of a tooltip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Preview deployment: https://inline-media-block.preview.avy-fx.org |
Create a shared DEFAULT_INLINE_BLOCKS constant (mirroring DEFAULT_BLOCKS pattern) and register it in all BlocksFeature configs so InlineMedia is available in Content, Callout, BlogList, HomePages, and Events editors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reuse the existing MediaBlock thumbnail for the inline media block inserter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
defaults.ts imports block configs (e.g. BlogListBlock), and those block configs now import DEFAULT_INLINE_BLOCKS from defaults.ts, creating a circular dependency. Move DEFAULT_INLINE_BLOCKS to a separate defaultInlineBlocks.ts file to break the cycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
rchlfryn
left a comment
There was a problem hiding this comment.
A lot of thinking out loud as review notes in the PR. Take em or leave em.
To answer your question about having both this and the ImageBlock, I think we should have both and get feedback from users on which makes more sense. I could see users wanting more inline blocks.
src/blocks/InlineMedia/config.ts
Outdated
| defaultValue: 'inline', | ||
| options: [ | ||
| { label: 'Inline', value: 'inline' }, | ||
| { label: 'Float left', value: 'float-left' }, |
There was a problem hiding this comment.
Interesting - for some reason I thought we were using camel case for values, but every other value is one word.
There was a problem hiding this comment.
Maybe update the labels to just be Left and Right? I am not sure float is needed here.
There was a problem hiding this comment.
Cool, I'm down for the label change - updated the description too: 61ba101
Interesting - for some reason I thought we were using camel case for values, but every other value is one word.
I almost always default to using snake case for unique values like keys like this or slugs. Just my preference 🤷♂️
src/blocks/InlineMedia/Component.tsx
Outdated
| className="block [&>span]:h-full [&_picture]:h-full [&_picture]:my-0" | ||
| style={{ height: `${fixedHeight}px` }} | ||
| > | ||
| <Media htmlElement="span" resource={media} imgClassName={imgSizeClass} sizes={sizes} /> |
There was a problem hiding this comment.
Any reason to not include pictureClassName="my-0" here?
| { label: '25% width', value: '25' }, | ||
| { label: '50% width', value: '50' }, | ||
| { label: '75% width', value: '75' }, | ||
| { label: '100% width', value: '100' }, |
There was a problem hiding this comment.
I don't think it matters, but maybe we add a w in front of of each value to ensure it's a string. Doesn't seem to be an issue.
There was a problem hiding this comment.
I like the idea, to make it clear that these are strings but we actually use these for the sizes attribute in the component so we'd have to strip off the 'w' prefix which I think would be more confusing.
| sizes = `${resolvedSize}vw` | ||
| } else if (isFixedHeight) { | ||
| imgSizeClass = 'h-full w-auto' | ||
| sizes = '96px' |
There was a problem hiding this comment.
How is this being calculated/ is it needed?
There was a problem hiding this comment.
This is the attribute — a hint that tells the browser which source to pick from a responsive srcset before layout is known. For fixed-height images the rendered width depends on the image's aspect ratio, which we don't have at render time without reading the media dimensions. 96px is a conservative fallback so the browser doesn't load the full-resolution source. It's imperfect but errs on the side of a smaller download; the browser will still render at the correct size.
| const mediaElement = isFixedHeight ? ( | ||
| <span | ||
| className="block [&>span]:h-full [&_picture]:h-full [&_picture]:my-0" | ||
| style={{ height: `${fixedHeight}px` }} |
There was a problem hiding this comment.
⛏️ You could make this a class name like you are above and remove the inline style.
There was a problem hiding this comment.
fixedHeight is dynamic so we can't use a classname here. See https://tailwindcss.com/docs/detecting-classes-in-source-files#dynamic-class-names:~:text=Don%27t%20use%20props%20to%20build%20class%20names%20dynamically
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The non-fixed-height path already passed this prop directly. The fixed-height path was achieving the same effect via a descendant selector, which was inconsistent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Description
Adds a new
InlineMediainline block for the Lexical rich text editor, allowing editors to embed images directly within text flow. Images can be positioned inline with configurable vertical alignment, or floated left/right with text wrapping.Related Issues
None, alternative to #961
Key Changes
InlineMediablock (src/blocks/InlineMedia/) — config and component for inline media in rich textinlineBlockHow to test
pnpm devand navigate to the admin panelScreenshots / Demo video
https://www.loom.com/share/a167f8e500824d60b88914fe6b66014b
Hmm I wonder if floats are too confusing to content editors when they can use them, unconstrained in the ContentBlock?

Migration Explanation
No migration needed — this adds a new inline block type to existing Lexical rich text fields. Existing content is unaffected.
Future enhancements / Questions
imageUrlin the block config using the same MediaThumbnail.jpg for when that gets fixed.